package nkr1pt.popkorn.helper;

import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.io.File;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TimerTask;
import java.util.logging.Logger;
import nkr1pt.popkorn.events.EventBus;
import nkr1pt.popkorn.events.PopkornEvent.EventType;
import nkr1pt.popkorn.events.PopkornEventFactory;

/**
 *
 * @author Kristof Vanhaeren
 */
@Singleton
public class PathWatcher extends TimerTask {

    private Logger logger = Logger.getLogger(getClass().getName());

    private EventBus eventBus;

    private PopkornEventFactory eventFactory;

    private String path;

    private Map<File, Long> oldFileMap = new HashMap<File, Long>();

    private Set<File> createdFiles;

    private Set<File> deletedFiles;

    private Set<File> modifiedFiles;
    
    @Inject
    public PathWatcher(EventBus eventBus, PopkornEventFactory eventFactory) {
        this.eventBus = eventBus;
        this.eventFactory = eventFactory;
    }

    @Override
    public void run() {
        createdFiles = new HashSet<File>();
        deletedFiles = new HashSet<File>();
        Map<File, Long> newFileMap = buildFileMap();
        if (!oldFileMap.keySet().equals(newFileMap.keySet())) {
            createdFiles = findCreatedFiles(oldFileMap.keySet(), newFileMap.keySet());
            deletedFiles = findDeletedFiles(oldFileMap.keySet(), newFileMap.keySet());
            oldFileMap = newFileMap;
        }

        modifiedFiles = findModifiedFiles(oldFileMap, newFileMap);
        for (File modifiedFile : modifiedFiles) {
            eventBus.fireEvent(eventFactory.newEvent(EventType.DOWNLOADCANDIDATE_MODIFIED, modifiedFile));
        }

        for (File createdFile : createdFiles) {
            eventBus.fireEvent(eventFactory.newEvent(EventType.DOWNLOADCANDIDATE_CREATED, createdFile));
        }

        for (File deletedFile : deletedFiles) {
            eventBus.fireEvent(eventFactory.newEvent(EventType.DOWNLOADCANDIDATE_DELETED, deletedFile));
        }
    }

    private Map<File, Long> buildFileMap() {
        Map<File, Long> fileMap = new HashMap<File, Long>();
        File rootDir = new File(path);
        for (File file : rootDir.listFiles()) {
            if (file.isFile() && !file.isHidden() && !file.getName().endsWith("~")) {
                fileMap.put(file, file.lastModified());
            }
        }

        return fileMap;
    }

    private Set<File> findCreatedFiles(Set<File> oldFiles, Set<File> newFiles) {
        Set<File> createdFilesFound = new HashSet<File>();
        createdFilesFound.addAll(newFiles);
        createdFilesFound.removeAll(oldFiles);
        return createdFilesFound;
    }

    private Set<File> findDeletedFiles(Set<File> oldFiles, Set<File> newFiles) {
        Set<File> deletedFilesFound = new HashSet<File>();
        deletedFilesFound.addAll(oldFiles);
        deletedFilesFound.removeAll(newFiles);
        return deletedFilesFound;
    }

    private Set<File> findModifiedFiles(Map<File, Long> oldFileMap, Map<File, Long> newFileMap) {
        Set<File> modifiedFilesFound = new HashSet<File>();
        for (Map.Entry<File,Long> entryOld : oldFileMap.entrySet()) {
            for (Map.Entry<File,Long> entryNew : newFileMap.entrySet()) {
                if (entryOld.getKey().equals(entryNew.getKey())) {
                    if (entryOld.getValue() < entryNew.getValue()) {
                        modifiedFilesFound.add(entryOld.getKey());
                    }
                }
                break;
            }
        }
        return modifiedFilesFound;
    }

    public Set<File> getCreatedFiles() {
        return createdFiles;
    }

    public Set<File> getDeletedFiles() {
        return deletedFiles;
    }

    public Set<File> getModifiedFiles() {
        return modifiedFiles;
    }

    public void setPath(String path) {
        this.path = path;
    }

}